/*
 ============================================================================
 Name        : CyS_TP2.c
 Author      : Aberg Cobo, Oybin & Tenaillon
 Version     :
 Copyright   : Your copyright notice
 Description : Criptography & Security in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "dicadt.h"
#include "extras.h"
#include "sha1.h"
#include "util.h"
#include "CyS_TP2.h"

#define USERS_FILE "passwd/USUARIOS06.enc"
#define SPY_FILE "./espia/ESPIA06.aes"
#define DICT_FILE "dict/diccio_mio.txt"

#define MAX_USR_LEN 16
#define MAX_PASS_LEN 40
#define HASH_RES 16

#define H_MASK 240
#define L_MASK 15

#define MAX_TXT_LEN     100
/* Funcion que me devuelve del archivo de usuarios, un nombre de usuario
 * y su contrasena encriptada.
 * En caso de haber un usuario, devuelve 1, caso contrario devuelve 0
 */
int GetUser(int users, unsigned char * u_name, unsigned char * e_pass);

/* Esta funcion agarra el vuelco hexadecimal del archivo y lo pasa a un
 * string de 16 caracteres para poder hacer el XOR
 */
void TransformHexDump(unsigned char * hex_dump, unsigned char * e_pass);
/* Esta funcion hace lo contrario a la anterior */
void ExpandToHex(unsigned char * e_pass, unsigned char * hex_dump);
int CharToHexInt(char Hex);
char IntToHexChar(int Int);
int getEncTxt(char * filename, char * enc);


int main(void) {
	puts("Trabajo Practico de Criptografia y Seguridad - 2009\n");

		int i, j;
		unsigned char u_name[MAX_USR_LEN] = {0};
		unsigned char hex_dump[MAX_PASS_LEN] = {0};
		unsigned char dic_word[MAX_WORD_LENGTH*3] = {0};
		unsigned char possible_pass[MAX_PASS_LEN] = {0};
		unsigned char XOR_Candidate[SHA_DIGEST_LENGTH] = {0};
		unsigned char e_pass[HASH_RES] = {0};
		unsigned char SHA_1_Result[SHA_DIGEST_LENGTH] = {0};
		int users;
		dicADT dic;
		SHA1Context sha;
		char enc_txt[MAX_TXT_LEN] = {0};
		char dec_txt[MAX_TXT_LEN] = {0};
		char encFile[MAX_TXT_LEN] = {0};
		int flag = 0;


	    sprintf(encFile, SPY_FILE);
	     if (getEncTxt(encFile, enc_txt) <= 0)
	     {
	         printf("Error en archivo ESPIA\n");
	         return 1;
	     }
		users = open(USERS_FILE, O_RDONLY);
		if( users == -1 ){
			fprintf(stdout, "Se ha producido un error abriendo el archivo de usuarios\n"
					"Finalizando la ejecucion del programa\n");
			return EXIT_FAILURE;
		}else fprintf(stdout, "Archivo de Usuarios abierto...\n");

		while(GetUser(users, u_name, hex_dump)){
		    flag = 0;
		    hex2byte(e_pass, hex_dump, 16);

			fprintf(stdout, "Nombre de Usuario: %s\nContrasena: %s\n", u_name, hex_dump);
			fprintf(stdout, "Primero probamos con numeros desde el 0 al 9999999...\n");
			for(i=0; i<10000000 && !flag; i++){
				memset(possible_pass, 0, MAX_PASS_LEN *sizeof(char));
				/* Concateno el Nombre de Usuario y la Palabra */
				sprintf(possible_pass, "%s%d", u_name, i);
				/* Ahora le calculo el hash SHA-1 */
				calculateHash(SHA_1_Result, possible_pass);
				/* Acorto el Resultado de SHA-1 a 32 Bytes*/
				SHA_1_Result[33] = 0;

				/* Ahora hago el Calculo del XOR bit a bit */
				for( j = 0; j < HASH_RES; j++){
					XOR_Candidate[j] = SHA_1_Result[j] ^ e_pass[j];
				}
				memset(hex_dump, 0, MAX_PASS_LEN*sizeof(char));
				ExpandToHex(XOR_Candidate, hex_dump);

				if (tryDecryptAes(enc_txt, strlen(enc_txt), (char *)XOR_Candidate))
				{
					 printf("Clave: %d\n", i);
					 flag = 1;
				}
			}

			/* Inicializo el Diccionario */
			dic = NewDic(DICT_FILE);
			if(dic == NULL){
				fprintf(stdout, "Se ha producido un error abriendo el archivo del Diccionario\n"
						"Finalizando la ejecucion del programa\n");
				close(users);
				return EXIT_FAILURE;
			}else fprintf(stdout, "Diccionario Inicializado...\nProbamos con palabras...\n");

			/* Ahora Ciclo por todas las palabras del Diccionario */
			clrTxt(dic_word, MAX_WORD_LENGTH*3);
			int j;
			char num_word[9] = {0};
			while(NextWord(dic, dic_word) && !flag)
			{
		         clrTxt(num_word, 9);
		         if(strlen(dic_word) < 8)
		         {
		             for(j = 0; j <= 9; j++)
		             {
		                 clrTxt(num_word, 9);
		                 sprintf(num_word, "%d%s", j, dic_word);

		                 /* llamo a la funcion */
		                 memset(possible_pass, 0, MAX_PASS_LEN *sizeof(char));
                        /* Concateno el Nombre de Usuario y la Palabra */
                        sprintf(possible_pass, "%s%s", u_name, num_word);
                        /* Ahora le calculo el hash SHA-1 */
                        calculateHash(SHA_1_Result, possible_pass);
                        /* Acorto el Resultado de SHA-1 a 32 Bytes*/
                        SHA_1_Result[33] = 0;

                        /* Ahora hago el Calculo del XOR bit a bit */
                        for( i = 0; i < HASH_RES; i++){
                            XOR_Candidate[i] = SHA_1_Result[i] ^ e_pass[i];
                        }
                        memset(hex_dump, 0, MAX_PASS_LEN*sizeof(char));
                        ExpandToHex(XOR_Candidate, hex_dump);

                        if (tryDecryptAes(enc_txt, strlen(enc_txt), (char *)XOR_Candidate))
                        {
                             printf("Clave: %s\n", num_word);
                             flag = 1;
                        }

		             }

		             for(j = 0; j <= 9; j++)
                     {
                         clrTxt(num_word, 9);
                         sprintf(num_word, "%s%d", dic_word, j);

                         /* llamo a la funcion */
                         memset(possible_pass, 0, MAX_PASS_LEN *sizeof(char));
                         /* Concateno el Nombre de Usuario y la Palabra */
                         sprintf(possible_pass, "%s%s", u_name, num_word);
                         /* Ahora le calculo el hash SHA-1 */
                         calculateHash(SHA_1_Result, possible_pass);
                         /* Acorto el Resultado de SHA-1 a 32 Bytes*/
                         SHA_1_Result[33] = 0;

                         /* Ahora hago el Calculo del XOR bit a bit */
                         for( i = 0; i < HASH_RES; i++){
                             XOR_Candidate[i] = SHA_1_Result[i] ^ e_pass[i];
                         }
                         memset(hex_dump, 0, MAX_PASS_LEN*sizeof(char));
                         ExpandToHex(XOR_Candidate, hex_dump);

                         if (tryDecryptAes(enc_txt, strlen(enc_txt), (char *)XOR_Candidate))
                         {
                              printf("Clave: %s\n", num_word);
                              flag = 1;
                         }

                     }
		         }

				memset(possible_pass, 0, MAX_PASS_LEN *sizeof(char));
				/* Concateno el Nombre de Usuario y la Palabra */
				sprintf(possible_pass, "%s%s", u_name, dic_word);
				/* Ahora le calculo el hash SHA-1 */
				calculateHash(SHA_1_Result, possible_pass);
				/* Acorto el Resultado de SHA-1 a 32 Bytes*/
				SHA_1_Result[33] = 0;

				/* Ahora hago el Calculo del XOR bit a bit */
				for( i = 0; i < HASH_RES; i++){
					XOR_Candidate[i] = SHA_1_Result[i] ^ e_pass[i];
				}
				memset(hex_dump, 0, MAX_PASS_LEN*sizeof(char));
				ExpandToHex(XOR_Candidate, hex_dump);

				if (tryDecryptAes(enc_txt, strlen(enc_txt), (char *)XOR_Candidate))
				{
				     printf("Clave: %s\n", dic_word);
				     flag = 1;
				}
				clrTxt(dic_word, MAX_WORD_LENGTH*3);

	        }

			FreeDic(dic);

		}

		close(users);

		return EXIT_SUCCESS;
}

int doIt (unsigned char * possible_pass, unsigned char * u_name, unsigned char * dic_word, unsigned char * hex_dump, unsigned char * e_pass, char * enc_txt)
{
	int i;
	unsigned char SHA_1_Result[SHA_DIGEST_LENGTH] = {0};
	unsigned char XOR_Candidate[SHA_DIGEST_LENGTH] = {0};

	/* Concateno el Nombre de Usuario y la Palabra */
	sprintf(possible_pass, "%s%s", u_name, dic_word);

	/* Ahora le calculo el hash SHA-1 */
	calculateHash(SHA_1_Result, possible_pass);
	/* Acorto el Resultado de SHA-1 a 32 Bytes*/
	SHA_1_Result[33] = 0;

	/* Ahora hago el Calculo del XOR bit a bit */
	for( i = 0; i < HASH_RES; i++){
		XOR_Candidate[i] = SHA_1_Result[i] ^ e_pass[i];
	}
	memset(hex_dump, 0, MAX_PASS_LEN*sizeof(char));
	ExpandToHex(XOR_Candidate, hex_dump);

	/* Una vez que tengo el Resultado de XOR, lo tengo que convertir
	 * al String de 32 caracteres expandiendo cada byte...
	 */
	if (tryDecryptAes(enc_txt, strlen(enc_txt), (char *)XOR_Candidate))
	{
	     printf("Clave: %s\n", dic_word);
	     return 0;
	}

	return 1;
}


int GetUser(int users, unsigned char * u_name, unsigned char * e_pass){
	int i = 0, tmp_c = 0, flag = 0, j = 0, qty = 0;

	(void) memset(u_name, 0, MAX_USR_LEN*sizeof(char));
	(void) memset(e_pass, 0, MAX_PASS_LEN*sizeof(char));

	while(((qty = read(users, &tmp_c, sizeof(char))) == sizeof(char))){
		if(tmp_c != '\n' && tmp_c != EOF)
		{
			if( tmp_c == ':'){
			/* Se termino el Nombre de Usuario */
				flag = 1;
			}else if(flag == 0){
				u_name[i++] = (char) tmp_c;
			}else if(flag == 1){
				e_pass[j++] = (char) tmp_c;
			}
		}
		else if(tmp_c == '\n')
		{
		    return 1;
		}
	}

	if(qty == 0 && i == 0)
		return 0;

	return 1;
}

void TransformHexDump(unsigned char * hex_dump, unsigned char * e_pass){
	int i, j;
	for(i = 0, j = 0; j < HASH_RES; i += 2, j++){
		e_pass[j] = CharToHexInt(hex_dump[i]) << 4;
		e_pass[j] += CharToHexInt(hex_dump[i+1]);
	}
	return;
}

void ExpandToHex(unsigned char * e_pass, unsigned char * hex_dump){
	int i, j;
	for(i = 0, j = 0; j < HASH_RES; i+=2, j++){
		hex_dump[i] = IntToHexChar(e_pass[j] >> 4);
		hex_dump[i+1] = IntToHexChar(e_pass[j] & 15);
	}
	return;
}

int CharToHexInt(char Hex){
	switch(Hex){
	case '0': return 0;
	case '1': return 1;
	case '2': return 2;
	case '3': return 3;
	case '4': return 4;
	case '5': return 5;
	case '6': return 6;
	case '7': return 7;
	case '8': return 8;
	case '9': return 9;
	case 'A': return 10;
	case 'B': return 11;
	case 'C': return 12;
	case 'D': return 13;
	case 'E': return 14;
	case 'F': return 15;
	}
}

char IntToHexChar(int Int){
	switch(Int){
	case 0: return '0';
	case 1: return '1';
	case 2: return '2';
	case 3: return '3';
	case 4: return '4';
	case 5: return '5';
	case 6: return '6';
	case 7: return '7';
	case 8: return '8';
	case 9: return '9';
	case 10: return 'A';
	case 11: return 'B';
	case 12: return 'C';
	case 13: return 'D';
	case 14: return 'E';
	case 15: return 'F';
		}
}

int isPossible (const char * dec)
{
    int i;
    int len = strlen(dec);
    for(i = 0; i < 16; i++)
    {
        if(dec[i] < 32 || dec[i] > 127)
            return 0;
    }
    return 1;
}

int getEncTxt(char * filename, char * enc)
{
    char ch;
    FILE * in;
    int i = 0;
    if((in = fopen(filename, "r")) == NULL)
    {
        printf("Path erroneo\n");
        return -1;
    }

    while(!feof(in))
    {
        ch = getc(in);

        if(ferror(in))
            return -1;
        else
        {
            if(!feof(in))
                enc[i++] = ch;

        }
    }
    return 1;
}

void clrTxt(char * str, int len)
{
    int i;
    for(i = 0; i < len; i++)
    {
        str[i] = 0;
    }
}
